﻿/// <Summary> 
/// $Author: Nikhil Chinchwade 
/// This file contains classes related to monitoring result data source

/// $Creation Date : 
/// </summary>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.WindowsAzure.StorageClient.Protocol;
using Microsoft.WindowsAzure.StorageClient.Tasks;
using System.Data.Services.Common;
using System.Data.Services.Client;
using MindTree.PerfWorkbench.Azure.Monitor.Core;
using MindTree.PerfWorkbench.Azure.Monitor.AzureMonLib.result;


namespace MindTree.PerfWorkbench.Azure.Monitor.AzureMonLib
{
    /// <summary>
    /// Class to represent ContinuationToken
    /// </summary>
    class ListRowsContinuationToken
    {
        public string PartitionKey { get; set; }
        public string RowKey { get; set; }
    }


    /// <summary>
    /// Class representing monitoring result data source
    /// </summary>
    public class PerfResultDataSource : PerfResultService
    {

        public delegate IEnumerable<PerfDataRow> AsyncMethodCaller();

        List<PerfDataRow> resultSet = new List<PerfDataRow>();
        
        private static DateTime startTime = DateTime.MinValue;

        private static PerfResultDataSource instance = null;

        public static PerfResultDataSource Instance
        {
            get
            {
                if (null == instance)
                {
                    instance = new PerfResultDataSource();
                }
                return instance;
            }
        }

        public static bool IsIitialized = false;

        /// <summary>
        /// Constructor
        /// </summary>
        private PerfResultDataSource()
        {
            StorageCredentials cred = new StorageCredentialsAccountAndKey(AzureMonInstanceContext.AzureApp.AppConnectionConfig.AccountName, AzureMonInstanceContext.AzureApp.AppConnectionConfig.AccountKey);  // AzureMonitorContext.GetInstance().StorageAccount;//new StorageCredentialsAccountAndKey(AzureMonitorContext.GetInstance().StorageAccount."ptfram", "mUn+yQmY9c1X9X7OhQe4pFUjaeXhHhAEKooQdTwk7PByyFAtAx4dhl42t05RlUYc5X1vCnobSegvzP6Zh3Qfgw==");
            _PerfDataContext = new PerfDataContext(AzureMonInstanceContext.AzureApp.AppConnectionConfig.TableBaseAddress, cred); 
        }

        private PerfDataContext _PerfDataContext;

        private List<PerfDataRow> monData = new List<PerfDataRow>();

        public List<PerfDataRow> MonData
        {
            get            
            {
                return monData;
            }
            set
            {
                monData = value;
                Notify();
            }

        }
         
        /// <summary>
        /// Get Next monitoring result set from Azure Storage
        /// </summary>
        /// <returns>Monitoring results as Enumerable dataset</returns>
        public IEnumerable<PerfDataRow> GetNext()
        {
            
            if (IsIitialized == false)
            {
                string str = GetLatestPartitionKey(TimeSpan.FromMinutes(1), 10);
                startTime = new DateTime(long.Parse(str.Substring(1)));                
                IsIitialized = true;
            }           

            /*DataServiceQuery<PerfDataRow> query = (DataServiceQuery < PerfDataRow > )from c in _PerfDataContext.PerfDataTable
                                                                                     where c.PartitionKey == "0" + startTime.Ticks.ToString()
                                                                                    select c;*/

            //CloudTableQuery<PerfDataRow> cloudTableQuery = query.AsTableServiceQuery<PerfDataRow>();

            ListRowsContinuationToken continuationToken = null;

            //try
            //{

            //    DataServiceQuery<PerfDataRow> query = (DataServiceQuery<PerfDataRow>)from c in _PerfDataContext.PerfDataTable
            //                                                                         where c.PartitionKey == "0" + startTime.Ticks.ToString()
            //                                                                         select c;

            //    query.BeginExecute(BeginExecuteSegmentedIsDone, query);

            //}
            //catch (DataServiceQueryException ex)
            //{
            //}
            //catch (DataServiceRequestException ex)
            //{
            //}
            //catch (DataServiceClientException ex)
            //{
            //}

            try
            {
                do
                {
                    DataServiceQuery<PerfDataRow> query = (DataServiceQuery<PerfDataRow>)from c in _PerfDataContext.PerfDataTable
                                                                                         where c.PartitionKey == "0" + startTime.Ticks.ToString()
                                                                                         select c;
                    if (null != continuationToken)
                    {
                        query = query.AddQueryOption("NextPartitionKey", continuationToken.PartitionKey);
                        if (null != continuationToken.RowKey)
                        {
                            query = query.AddQueryOption("NextRowKey", continuationToken.RowKey);
                        }
                    }
                    var response = query.Execute() as QueryOperationResponse;
                    resultSet.AddRange(response.Cast<PerfDataRow>());

                    if (response.Headers.ContainsKey("x-ms-continuation-NextPartitionKey"))
                    {
                        continuationToken = new ListRowsContinuationToken();
                        continuationToken.PartitionKey = response.Headers["x-ms-continuation-NextPartitionKey"];
                        if (response.Headers.ContainsKey("x-ms-continuation-NextRowKey"))
                        {
                            continuationToken.RowKey = response.Headers["x-ms-continuation-NextRowKey"];
                        }
                    }
                    else
                    {
                        continuationToken = null;
                    }

                } while (null != continuationToken);

                if (resultSet.Count() <= 0)
                {
                    return null;
                }
                MonData = resultSet;
                resultSet.Clear();
                CSVExport.ExportNow();
            }
            catch (DataServiceQueryException ex)
            {
            }
            catch (DataServiceRequestException ex)
            {
            }
            catch (DataServiceClientException ex)
            {
            }
            startTime = startTime.AddMinutes(1);
            return MonData;           
        }

        /// <summary>
        /// Async result extraction from Azure Storage
        /// </summary>
        /// <param name="result">Async result object</param>
        private void BeginExecuteSegmentedIsDone(IAsyncResult result)
        {
           
            ListRowsContinuationToken contToken = null;
            DataServiceQuery<PerfDataRow> dataServiceQuery = result.AsyncState as DataServiceQuery<PerfDataRow>;
            IEnumerable<PerfDataRow> data = dataServiceQuery.EndExecute(result);
            
            resultSet.AddRange( data.ToList<PerfDataRow>() );  
            
            var response = data as QueryOperationResponse;
            
            if (response.Headers.ContainsKey("x-ms-continuation-NextPartitionKey"))
                    {
                        contToken = new ListRowsContinuationToken();
                        contToken.PartitionKey = response.Headers["x-ms-continuation-NextPartitionKey"];
                        if (response.Headers.ContainsKey("x-ms-continuation-NextRowKey"))
                        {                            
                            contToken.RowKey = response.Headers["x-ms-continuation-NextRowKey"];
                        }
                        DataServiceQuery<PerfDataRow> query = (DataServiceQuery<PerfDataRow>)from c in _PerfDataContext.PerfDataTable
                                                                                             where c.PartitionKey == "0" + startTime.Ticks.ToString()
                                                                                             select c;

                        query = query.AddQueryOption("NextPartitionKey", contToken.PartitionKey);
                        if (null != contToken.RowKey)
                        {
                            query = query.AddQueryOption("NextRowKey", contToken.RowKey);
                        }

                        IAsyncResult res = query.BeginExecute(BeginExecuteSegmentedIsDone, query);
                    }
                    else
                    {
                        contToken = null;
                    }                           
    
            MonData.AddRange(resultSet);
            MonData = MonData;         
            resultSet.Clear();  
        }


        /// <summary>
        /// Retrieve latest azure storage table partition key containing monitoring results
        /// </summary>
        /// <param name="ScheduledTransferTime">Transfer period</param>
        /// <param name="totalretries">Number of retries in case of error</param>
        /// <returns>Partition key as String</returns>
        private string GetLatestPartitionKey(TimeSpan ScheduledTransferTime, int totalretries)
        {
            if (totalretries == 0)
            {
                return null;
            }
            DateTime currentGMT = WebTimeClient.GetCurrentGMT();
            if( currentGMT.Equals(DateTime.MinValue))
            {

            }
            DateTime curTime = new DateTime(currentGMT.Year, currentGMT.Month, currentGMT.Day, currentGMT.Hour, currentGMT.Minute, 00);

            DateTime prevTime = curTime.Subtract(ScheduledTransferTime);
            
            //var partkey = (DataServiceQuery<PerfDataRow>)from c in _PerfDataContext.PerfDataTable
            //                                             where c.PartitionKey.CompareTo("0" + prevTime.Ticks.ToString()) >= 0 && c.PartitionKey.CompareTo("0" + curTime.Ticks.ToString()) <= 0
            //                                             select c;

            //var partkey = (DataServiceQuery<PerfDataRow>)from c in _PerfDataContext.PerfDataTable                                                        
            //                                            where c.PartitionKey.CompareTo("0" + prevTime.Ticks.ToString()) >= 0 && c.PartitionKey.CompareTo("0" + curTime.Ticks.ToString()) <= 0
            //                                            select c;

            //var res = partkey.Execute().ToList<PerfDataRow>();
            List<PerfDataRow> res = new List<PerfDataRow>();

            ListRowsContinuationToken continuationToken = null;

            do
            {

                var query = (DataServiceQuery<PerfDataRow>)from c in _PerfDataContext.PerfDataTable
                                                             where c.PartitionKey.CompareTo("0" + prevTime.Ticks.ToString()) >= 0 && c.PartitionKey.CompareTo("0" + curTime.Ticks.ToString()) <= 0
                                                             select c;
              
                if (null != continuationToken)
                {
                    query = query.AddQueryOption("NextPartitionKey", continuationToken.PartitionKey);
                    if (null != continuationToken.RowKey)
                    {
                        query = query.AddQueryOption("NextRowKey", continuationToken.RowKey);
                    }
                }
                try
                {

                    var response = query.Execute() as QueryOperationResponse;
                    res.AddRange(response.Cast<PerfDataRow>());

                    if (response.Headers.ContainsKey("x-ms-continuation-NextPartitionKey"))
                    {
                        continuationToken = new ListRowsContinuationToken();
                        continuationToken.PartitionKey = response.Headers["x-ms-continuation-NextPartitionKey"];
                        if (response.Headers.ContainsKey("x-ms-continuation-NextRowKey"))
                        {
                            continuationToken.RowKey = response.Headers["x-ms-continuation-NextRowKey"];
                        }
                    }
                    else
                    {
                        continuationToken = null;
                    }
                }
                catch (Exception ex)
                {

                }

            } while (null != continuationToken);
            

            if (res.Count == 0)
            {
                return GetLatestPartitionKey(ScheduledTransferTime.Add(ScheduledTransferTime), totalretries--);
            }
            string MaxPartitionNo = res.OrderByDescending(a => a.PartitionKey).First().PartitionKey;
            
            if ( null == MaxPartitionNo || MaxPartitionNo == "")
            {
                return GetLatestPartitionKey(ScheduledTransferTime.Add(ScheduledTransferTime), totalretries--);
            }

            return GetBufferedPartitionKey(MaxPartitionNo);
        }

        /// <summary>
        /// Extract buffered partition key
        /// </summary>
        /// <param name="parampartitionkey"></param>
        /// <returns></returns>
        private string GetBufferedPartitionKey(string parampartitionkey)
        {
            long partitionkey = long.Parse(parampartitionkey.Substring(1));
            partitionkey = partitionkey - TimeSpan.TicksPerMinute;
            return "0" + partitionkey;
        }

        private String GetOldestPartitionKey()
        {
            return "";
        }

    }

}
 